need to drop MRN and patient_name, replacing with study_id, once this becomes a research project

Aims and Hypotheses

Hypothesis 1: Discordance is a relatively common, yet under appreciated phenomenon, and varies by geographic location of care and patient attributes including demographics, severity of illness, and underlying disease process.

Hypothesis 2: Discordance between aPTT and anti-Xa indicates the presence of coagulation system pathophysiology which is a risk factor for development of hemorrhage and thrombosis.

Classic systemic anticoagulation goals, anti-Xa vs aPTT, at NYP:

Typical anti-Xa goal vs aPTT goals among heparinized ECMO patients:

Methods:

Only first ECMO run used.

ECMO duration: Dr. Connie Nguyen manually reviewed heparin-exposed patients’ EMRs in June 2025 to identify true ECMO time off, as initial data review identified some labs that were drawn while on heparin but after the patient was off ECMO. The variable “time_off” in the original data was obtained from ELSO sources. Per Dr. Nguyen’s review, if her evaluation of ECMO stop time was within 4 hours of ELSO-derived time_off, then the actual true time off was deemed as that known by ELSO. If there was a greater than 4 hour discrepancy, a new time_off_true value was recorded.

Lab cutoffs:

Hyperbilirubinemia can artifactually elevate anti-Xa (colorimetric assay). Jaundice threshold is 2 - 3 mg/dL total bilirubin. Upper limit of normal total bilirubin at NYP-CUIMC is 1.2 mg/dL.

need to redo all analyses, starting with run_labs_complications_raw, checking to ensure counts are correct, now that dataframe includes true ECMO stop times

Tidy Data, Heparin exposed

count of distinct MRNs of patients exposed to heparin
n
166
counts of MRNs of patients exposed to heparin by location; counts between distinct MRNs and department_name may not match as some patients move between departments
department_name n
MIL 5 CTICU 76
MIL 5 CCU 41
MIL 4 MICU A 31
HRT CARDIAC CARE 26
MIL OPERATING ROOM 5
MIL 4 SICU 1
MIL CARDIAC CATH 1
GBG 4 W CT ICU 1
MIL 9 HUDSON 1
MIL 5 GARDEN NORTH 1

Discordance Data, Heparin exposed

## Warning: There were 2 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `results = map(data, group_chisq)`.
## ℹ In group 8: `concordance_category = high aPTT low antiXa`.
## Caused by warning in `chisq.test()`:
## ! Chi-squared approximation may be incorrect
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
concordance_category classic low statistic p.value method
concordant low 250 72 98.398 0.000 Chi-squared test for given probabilities
low aPTT 141 139 0.014 0.905 Chi-squared test for given probabilities
concordant 133 173 5.229 0.022 Chi-squared test for given probabilities
high antiXa 7 47 29.630 0.000 Chi-squared test for given probabilities
concordant high 14 93 58.327 0.000 Chi-squared test for given probabilities
high aPTT 30 52 5.902 0.015 Chi-squared test for given probabilities
low antiXa 13 12 0.040 0.841 Chi-squared test for given probabilities
high aPTT low antiXa 1 1 0.000 1.000 Chi-squared test for given probabilities
low aPTT high antiXa 1 1 0.000 1.000 Chi-squared test for given probabilities
## Warning: There were 2 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `results = map(data, group_chisq)`.
## ℹ In group 4: `concordance = high aPTT low antiXa`.
## Caused by warning in `chisq.test()`:
## ! Chi-squared approximation may be incorrect
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
count and chi-square count data hypothesis testing for concordant LABS
concordance classic low statistic p.value method
concordant 794 676 9.472 0.002 Chi-squared test for given probabilities
discordant aPTT below antiXa 296 372 8.647 0.003 Chi-squared test for given probabilities
discordant aPTT above antiXa 86 128 8.243 0.004 Chi-squared test for given probabilities
high aPTT low antiXa 2 2 0.000 1.000 Chi-squared test for given probabilities
low aPTT high antiXa 2 2 0.000 1.000 Chi-squared test for given probabilities
count of distinct MRNs receiving heparin with time-matched aPTT and anti-Xa
n
115
counts of MRNs by location; counts between distinct MRNs and department_name may not match as some patients move between departments
department_name n
MIL 5 CTICU 56
MIL 5 CCU 31
HRT CARDIAC CARE 23
MIL 4 MICU A 7
MIL 4 SICU 1
MIL OPERATING ROOM 1
MIL CARDIAC CATH 1
GBG 4 W CT ICU 1
MIL 9 HUDSON 1
MIL 5 GARDEN NORTH 1
counts of labs in each location
department_name n
MIL 5 CTICU 227
MIL 5 CCU 202
HRT CARDIAC CARE 140
MIL 4 MICU A 11
GBG 4 W CT ICU 3
MIL 5 GARDEN NORTH 3
MIL 4 SICU 1
MIL OPERATING ROOM 1
MIL CARDIAC CATH 1
MIL 9 HUDSON 1

Discordance and Complications, Heparin Exposed

Demographics

basic demographics of discordant groups, each mrn with one group only
discordance_group n
concordant 17
discordant aPTT above antiXa 22
discordant aPTT below antiXa 57
mixed 19
counts of support type by discordant groups, each mrn with one group only
name concordant discordant aPTT above antiXa discordant aPTT below antiXa mixed
n 17.0 21.0 56.0 19.0
median_age 54.0 56.0 59.5 56.0
iqr_age 30.0 24.0 20.2 16.5
male_pct 58.8 57.1 71.4 52.6
median_wt 76.0 83.2 87.8 88.5
iqr_wt 21.5 26.6 29.6 29.6
median_ht 170.0 170.0 170.7 165.1
iqr_ht 10.1 15.8 12.8 15.2
median_hours 64.0 124.0 119.5 242.0
iqr_hours 107.0 119.0 117.8 175.0
discordance_group n pct_Cardiac pct_Pulmonary pct_ECPR
concordant 10 58.8 0.0 0.0
concordant 7 0.0 41.2 0.0
discordant aPTT above antiXa 16 76.2 0.0 0.0
discordant aPTT above antiXa 2 0.0 0.0 9.5
discordant aPTT above antiXa 3 0.0 14.3 0.0
discordant aPTT below antiXa 38 67.9 0.0 0.0
discordant aPTT below antiXa 3 0.0 0.0 5.4
discordant aPTT below antiXa 15 0.0 26.8 0.0
mixed 16 84.2 0.0 0.0
mixed 1 0.0 0.0 5.3
mixed 2 0.0 10.5 0.0
## Warning: There were 12 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `results = map(data, group_chisq_complications_once)`.
## ℹ In group 5: `hypothetical_treatment = "classic"` and `complication =
##   "hemorrhagic_peripheral_cannulation_site_bleeding"`.
## Caused by warning in `chisq.test()`:
## ! Chi-squared approximation may be incorrect
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 11 remaining warnings.
## # A tibble: 24 × 11
## # Groups:   hypothetical_treatment, complication [24]
##    complication       hypothetical_treatment statistic  p.value method data.name
##    <chr>              <chr>                      <dbl>    <dbl> <chr>  <chr>    
##  1 death_date         classic                     2.62  0.455   Chi-s… <NA>     
##  2 death_date         low                        11.8   0.00793 Chi-s… <NA>     
##  3 metabolic_hyperbi… classic                     0.4   0.819   Chi-s… <NA>     
##  4 metabolic_hyperbi… low                         0.4   0.819   Chi-s… <NA>     
##  5 mechanical_circui… classic                     0     1       Chi-s… <NA>     
##  6 mechanical_circui… low                         0     1       Chi-s… <NA>     
##  7 hemorrhagic_perip… classic                     0     1       Chi-s… <NA>     
##  8 hemorrhagic_perip… low                         0     1       Chi-s… <NA>     
##  9 neurologic_cns_in… classic                    NA    NA       Only … <NA>     
## 10 neurologic_cns_in… low                        NA    NA       Only … <NA>     
## # ℹ 14 more rows
## # ℹ 5 more variables: concordant <int>, `discordant aPTT above antiXa` <int>,
## #   `discordant aPTT below antiXa` <int>, mixed <int>,
## #   `low aPTT high antiXa` <int>
## Warning: There were 2 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `results = map(data, group_chisq_complications_once)`.
## ℹ In group 2: `hypothetical_treatment = "classic"` and
##   `hemorrhage_thrombosis_death = "hemorrhage_or_thrombosis"`.
## Caused by warning in `chisq.test()`:
## ! Chi-squared approximation may be incorrect
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
analysis based on counting each patient once, focused on composite of hemorrhagic + thrombotic complications (mechanical circuit change, hemorrhagic peripheral site bleeding, hemorrhagic GI bleeding, hemorrhagic surgical site bleeding) OR death
hypothetical_treatment hemorrhage_thrombosis_death statistic p.value method concordant discordant aPTT above antiXa discordant aPTT below antiXa mixed
classic death 2.6153846 0.4547988 Chi-squared test for given probabilities 9 4 8 5
low death 11.8461538 0.0079292 Chi-squared test for given probabilities 5 4 14 3
classic hemorrhage_or_thrombosis 1.5714286 0.6658854 Chi-squared test for given probabilities 3 1 1 2
low hemorrhage_or_thrombosis 0.4285714 0.9342791 Chi-squared test for given probabilities 2 2 2 1
## Warning: There were 2 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `results = map(data, group_chisq_complications_once)`.
## ℹ In group 2: `hypothetical_treatment = "classic"` and
##   `hemorrhage_thrombosis_death = "hemorrhage_or_thrombosis"`.
## Caused by warning in `chisq.test()`:
## ! Chi-squared approximation may be incorrect
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
analysis based on counting each patient once, focused on composite of hemorrhagic + thrombotic complications (mechanical circuit change, hemorrhagic peripheral site bleeding, hemorrhagic GI bleeding, hemorrhagic surgical site bleeding) OR death AND filtering out patients with hyperbilirubinemia > 2.5 mg/dL (which may increase anti-Xa artifactually
hypothetical_treatment hemorrhage_thrombosis_death statistic p.value method concordant discordant aPTT above antiXa discordant aPTT below antiXa mixed
classic death 2.6153846 0.4547988 Chi-squared test for given probabilities 9 4 8 5
low death 11.8461538 0.0079292 Chi-squared test for given probabilities 5 4 14 3
classic hemorrhage_or_thrombosis 1.5714286 0.6658854 Chi-squared test for given probabilities 3 1 1 2
low hemorrhage_or_thrombosis 0.4285714 0.9342791 Chi-squared test for given probabilities 2 2 2 1
## Warning: There were 2 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `results = map(data, group_chisq_complications_once)`.
## ℹ In group 2: `hypothetical_treatment = "classic"` and
##   `hemorrhage_thrombosis_death = "hemorrhage_or_thrombosis"`.
## Caused by warning in `chisq.test()`:
## ! Chi-squared approximation may be incorrect
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
analysis based on counting each patient once, focused on composite of hemorrhagic + thrombotic complications (mechanical circuit change, hemorrhagic peripheral site bleeding, hemorrhagic GI bleeding, hemorrhagic surgical site bleeding) OR death with all discordance grouped together
hypothetical_treatment hemorrhage_thrombosis_death statistic p.value method concordant discordant
classic death 2.4615385 0.1166645 Chi-squared test for given probabilities 9 17
low death 9.8461538 0.0017019 Chi-squared test for given probabilities 5 21
classic hemorrhage_or_thrombosis 0.1428571 0.7054570 Chi-squared test for given probabilities 3 4
low hemorrhage_or_thrombosis 1.2857143 0.2568393 Chi-squared test for given probabilities 2 5

Polynomial Fitting

# Fit mixed-effects model with random intercept for patient (mrn)
discordance_model <- lmer(
  heparin_assay_quantitative ~ poly(activated_partial_thromboplastin_time, 2) + (1 | mrn),
  data = discordance_data)

# Create prediction grid over the range of predictor
new_data <- data.frame(
  activated_partial_thromboplastin_time = seq(
    min(discordance_data$activated_partial_thromboplastin_time, na.rm = TRUE),
    max(discordance_data$activated_partial_thromboplastin_time, na.rm = TRUE),
    length.out = 300  ),
  mrn = discordance_data$mrn[1]  # Assign any existing patient ID for prediction
)

pred_interval <- merTools::predictInterval(
  discordance_model,          # model as first argument, no name
  newdata = new_data,
  level = 0.99,
  n.sims = 1000,
  which = "fixed",
  include.resid.var = TRUE)

# Bind predictions to the new_data
new_data <- bind_cols(new_data, pred_interval)

# Flag unusual data points outside prediction intervals
discordance_data =
  discordance_data %>%
  rowwise() %>%
  mutate(
    # Find closest prediction row by activated_partial_thromboplastin_time
    pred_row = list(new_data[which.min(abs(activated_partial_thromboplastin_time - new_data$activated_partial_thromboplastin_time)), ]),
    predicted = pred_row$fit,
    lower = pred_row$lwr,
    upper = pred_row$upr,
    unusual = heparin_assay_quantitative < lower | heparin_assay_quantitative > upper
  ) %>%
  ungroup()

# Plot predictions with prediction intervals and flagged unusual points
ggplot() +
  geom_ribbon(data = new_data,
              aes(x = activated_partial_thromboplastin_time, ymin = lwr, ymax = upr),
              fill = "blue", alpha = 0.2) +
  geom_line(data = new_data,
            aes(x = activated_partial_thromboplastin_time, y = fit),
            color = "blue") +
  geom_point(data = discordance_data,
             aes(x = activated_partial_thromboplastin_time, y = heparin_assay_quantitative, color = unusual)) +
  scale_color_manual(values = c("black", "red")) +
  labs(
    color = "Unusual",
    title = "Mixed Model Fit with 99% Prediction Interval",
    x = "Activated Partial Thromboplastin Time",
    y = "Heparin Assay Quantitative"
  ) +
  theme_minimal()

discordance_data
## # A tibble: 1,180 × 17
##    mrn   patient_name lab_result_time     department_name heparin_infusion_dos…¹
##    <chr> <chr>        <dttm>              <fct>           <chr>                 
##  1 1000… AHMED, AMENA 2024-11-03 23:47:00 MIL 5 CCU       5                     
##  2 1000… AHMED, AMENA 2024-11-03 23:47:00 MIL 5 CCU       5                     
##  3 1000… AHMED, AMENA 2024-11-04 06:41:00 MIL 5 CCU       5                     
##  4 1000… AHMED, AMENA 2024-11-04 06:41:00 MIL 5 CCU       5                     
##  5 1000… AHMED, AMENA 2024-11-04 15:35:00 MIL 5 CCU       5                     
##  6 1000… AHMED, AMENA 2024-11-04 15:35:00 MIL 5 CCU       5                     
##  7 1000… AHMED, AMENA 2024-11-04 19:18:00 MIL 5 CCU       5                     
##  8 1000… AHMED, AMENA 2024-11-04 19:18:00 MIL 5 CCU       5                     
##  9 1000… AHMED, AMENA 2024-11-05 06:44:00 MIL 5 CCU       5                     
## 10 1000… AHMED, AMENA 2024-11-05 06:44:00 MIL 5 CCU       5                     
## # ℹ 1,170 more rows
## # ℹ abbreviated name: ¹​heparin_infusion_dose_value_units_kg_hr
## # ℹ 12 more variables: concordance_classic_simple <fct>,
## #   concordance_low_simple <fct>, discordance_group <fct>,
## #   hypothetical_treatment <chr>, concordance_category <fct>,
## #   activated_partial_thromboplastin_time <dbl>,
## #   heparin_assay_quantitative <dbl>, pred_row <list>, predicted <dbl>, …

Note that patients can count in multiple renal failure categories. I.e. Patient X is included in renal Cr 1.5 - 3.0 AND Cr > 3.0.

We need thrombotic complications:

We need additional hemorrhagic complications:

What are the actual ranges of aPTT and anti-Xa among those with completely concordant versus discordant categories? Why are there different death outcomes? Are the demographics different? Disease processes?